home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / mpwtools.cpt / misc src / xbin.c < prev   
Encoding:
C/C++ Source or Header  |  1991-09-24  |  21.2 KB  |  1,080 lines

  1. #ifndef lint
  2. static char version[] = "xbin.c Version 3.0 09/30/89";
  3. #endif lint
  4. #include <stdio.h>
  5. #include <errno.h>
  6.  
  7. #ifndef    MPW
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <sys/dir.h>
  11. #else    MPW
  12. #include <Types.h>
  13. #include <Files.h>
  14. #include <Memory.h>
  15. #include <ErrMgr.h>
  16. #include <StdLib.h>
  17. #include <String.h>
  18. #include <CursorCtl.h>
  19. #define     FALSE 0
  20. #define     TRUE 1
  21. /* stops linker linking these in */
  22. ecvt() {}
  23. fcvt() {}
  24. #endif    MPW
  25. extern int errno;
  26.  
  27. #ifdef MAXNAMLEN    /* 4.2 BSD */
  28. #define FNAMELEN MAXNAMLEN
  29. #else
  30. #define FNAMELEN DIRSIZ
  31. #endif
  32.  
  33. #ifdef BSD
  34. #include <sys/time.h>
  35. #include <sys/timeb.h>
  36. #define search_last rindex
  37. extern char *rindex();
  38. #else
  39. #include <time.h>
  40. extern long timezone;
  41. #define search_last strrchr
  42. extern char *strrchr();
  43. #endif
  44.  
  45. /* Mac time of 00:00:00 GMT, Jan 1, 1970 */
  46. #define TIMEDIFF 0x7c25b080
  47.  
  48. #define DATABYTES 128
  49.  
  50. #define BYTEMASK 0xff
  51. #define BYTEBIT 0x100
  52. #define WORDMASK 0xffff
  53. #define WORDBIT 0x10000
  54.  
  55. #define NAMEBYTES 63
  56. #define H_NLENOFF 1
  57. #define H_NAMEOFF 2
  58.  
  59. /* 65 <-> 80 is the FInfo structure */
  60. #define H_TYPEOFF 65
  61. #define H_AUTHOFF 69
  62. #define H_FLAGOFF 73
  63.  
  64. #define H_LOCKOFF 81
  65. #define H_DLENOFF 83
  66. #define H_RLENOFF 87
  67. #define H_CTIMOFF 91
  68. #define H_MTIMOFF 95
  69.  
  70. #define H_OLD_DLENOFF 81
  71. #define H_OLD_RLENOFF 85
  72.  
  73. #define F_BUNDLE 0x2000
  74. #define F_LOCKED 0x8000
  75.  
  76. struct macheader {
  77.     char m_name[NAMEBYTES+1];
  78.     char m_type[4];
  79.     char m_author[4];
  80.     short m_flags;
  81.     long m_datalen;
  82.     long m_rsrclen;
  83.     long m_createtime;
  84.     long m_modifytime;
  85. } mh;
  86.  
  87. struct filenames {
  88.     char f_info[256];
  89.     char f_data[256];
  90.     char f_rsrc[256];
  91. } files;
  92.  
  93. int pre_beta;    /* options */
  94. int listmode;
  95. int verbose;
  96.  
  97. int compressed;    /* state variables */
  98. int qformat;
  99. int header_found = FALSE;
  100. FILE *ifp = NULL;
  101. long get4q();
  102.  
  103. /*
  104.  * xbin -- unpack BinHex format file into suitable
  105.  * format for downloading with macput
  106.  * Dave Johnson, Brown University Computer Science
  107.  *
  108.  * (c) 1984 Brown University
  109.  * may be used but not sold without permission
  110.  *
  111.  * created ddj 12/16/84
  112.  * revised ddj 03/10/85 -- version 4.0 compatibility, other minor mods
  113.  * revised ddj 03/11/85 -- strip LOCKED bit from m_flags
  114.  * revised ahm 03/12/85 -- System V compatibility
  115.  * revised dba 03/16/85 -- (Darin Adler, TMQ Software)  4.0 EOF fixed,
  116.  *               4.0 checksum added
  117.  * revised ddj 03/17/85 -- extend new features to older formats: -l, stdin
  118.  * revised ddj 03/24/85 -- check for filename truncation, allow multiple files
  119.  * revised ddj 03/26/85 -- fixed USG botches, many problems w/multiple files
  120.  * revised jcb 03/30/85 -- (Jim Budler, amdcad!jimb), revised for compatibility
  121.  *               with 16-bit int machines
  122.  * revised dl  06/16/85 -- (Dan LaLiberte, liberte@uiucdcs) character
  123.  *               translation speedup
  124.  * revised ddj 09/30/85 -- fixed problem with run of RUNCHAR
  125.  * revised sw  09/30/89 -- much hacked about to work with MPW
  126.  */
  127. char usage[] = "usage: \"xbin [-v] [-l] [-o] [-n name] [-] filename\"\n";
  128.  
  129. main(ac, av)
  130. char **av;
  131. {
  132.     char *filename, *macname;
  133.  
  134. #ifdef    MPW
  135.     InitCursorCtl(nil);
  136. #endif    MPW
  137.     filename = ""; macname = "";
  138.     ac--; av++;
  139.     while (ac) {
  140.         if (av[0][0] == '-') {
  141.             switch (av[0][1]) {
  142.             case '\0':
  143.                 filename = "-";
  144.                 break;
  145.             case 'v':
  146.                 verbose++;
  147.                 break;
  148.             case 'l':
  149.                 listmode++;
  150.                 break;
  151.             case 'o':
  152.                 pre_beta++;
  153.                 break;
  154.             case 'n':
  155.                 if (ac > 1) {
  156.                     ac--; av++;
  157.                     macname = av[0];
  158.                     filename = "";
  159.                     break;
  160.                 }
  161.                 else
  162.                     goto bad_usage;
  163.             default:
  164.                 goto bad_usage;
  165.             }
  166.         }
  167.         else
  168.             filename = av[0];
  169.         if (filename[0] != '\0') {
  170.             do {
  171.                 setup_files(filename, macname);
  172.                 if (listmode) {
  173.                     print_header();
  174.                 }
  175.                 else {
  176.                     process_forks();
  177.                     /* now that we know the size of the forks */
  178.                     forge_info();
  179.                 }
  180.                 macname = "";
  181.                 qformat = 0;
  182.                 compressed = 0;
  183.             } while (!feof(ifp));
  184.             fclose(ifp);
  185.             ifp = NULL;        /* reset state */
  186.             header_found = FALSE;
  187.         }
  188.         ac--; av++;
  189.     }
  190.     if (*filename == '\0') {
  191. bad_usage:
  192.         fprintf(stderr, usage);
  193.         exit(1);
  194.     }
  195. }
  196.  
  197. static char *extensions[] = {
  198.     ".hqx",
  199.     ".hcx",
  200.     ".hex",
  201.     "",
  202.     NULL
  203. };
  204.  
  205. setup_files(filename, macname)
  206. char *filename;        /* input file name -- extension optional */
  207. char *macname;        /* name to use on the mac side of things */
  208. {
  209.     char **ep;
  210.     static char namebuf[256];
  211. #ifndef    MPW
  212.     int n;
  213.     char *np;
  214.     struct stat stbuf;
  215. #else    MPW
  216.     FInfo    finderInfo;
  217. #endif    MPW
  218.     long curtime;
  219. #ifdef    MPW
  220.     OSType    f_creator, f_type;
  221. #endif    MPW
  222.     if (ifp == NULL) {
  223.         if (filename[0] == '-') {
  224.             ifp = stdin;
  225. #ifdef    MPW
  226.             filename = "Dev:Stdin";
  227. #else    MPW
  228.             filename = "stdin";
  229. #endif    MPW
  230.             strcpy (namebuf, filename);
  231.         }
  232.         else {
  233.             /* find input file and open it */
  234. #ifdef    MPW
  235.             if (filename[0] == 'ñ') {
  236.                 namebuf[0] = 'ñ';
  237.                 namebuf[1] = '\0';
  238.             }
  239.             else {
  240. #endif    MPW
  241.                 for (ep = extensions; *ep != NULL; ep++) {
  242.                     sprintf(namebuf, "%s%s", filename, *ep);
  243. #ifndef    MPW
  244.                     if (stat(namebuf, &stbuf) == 0)
  245.                         break;
  246. #else    MPW
  247.                     c2pstr(namebuf);
  248.                     if (GetFInfo (namebuf, 0, &finderInfo) == noErr) {
  249.                         p2cstr(namebuf);
  250.                         break;
  251.                     }
  252.                     p2cstr(namebuf);
  253. #endif    MPW
  254.                 }
  255.                 if (*ep == NULL) {
  256.                     perror(namebuf);
  257.                     exit(-1);
  258.                 }
  259.             }
  260.             ifp = fopen(namebuf, "r");
  261.             if (ifp == NULL) {
  262.                 perror(namebuf);
  263.                 exit(-1);
  264.             }
  265.         }
  266.     }
  267.     if (ifp == stdin) {
  268.         curtime = time(0);
  269.         mh.m_createtime = curtime;
  270.         mh.m_modifytime = curtime;
  271.     }
  272.     else {
  273. #ifndef    MPW
  274.         mh.m_createtime = stbuf.st_mtime;
  275.         mh.m_modifytime = stbuf.st_mtime;
  276. #endif    MPW
  277.     }
  278.     qformat = find_header(); /* eat mailer header &cetera, intuit format */
  279.     header_found = TRUE;
  280.     
  281.     if (qformat)
  282.         do_q_header(macname);
  283.     else
  284.         do_o_header(macname, filename);
  285.     if (listmode || verbose) {
  286.         fprintf(stderr, "%s %s%s",
  287.             listmode ? "Listing" : "Converting",
  288.             namebuf, listmode ? ":\n" : " ");
  289.     }
  290. #ifndef    MPW
  291.     /* make sure host file name doesn't get truncated beyond recognition */
  292.     n = strlen(mh.m_name);
  293.     if (n > FNAMELEN - 2)
  294.         n = FNAMELEN - 2;
  295.     strncpy(namebuf, mh.m_name, n);
  296.     namebuf[n] = '\0';
  297.     /* get rid of troublesome characters */
  298.     for (np = namebuf; *np; np++)
  299.         if (*np <= ' ' || *np == '/' || *np >= '\177')
  300.             *np = '_';
  301.  
  302.     sprintf(files.f_data, "%s.data", namebuf);
  303.     sprintf(files.f_rsrc, "%s.rsrc", namebuf);
  304.     sprintf(files.f_info, "%s.info", namebuf);
  305.     if (verbose)
  306.         fprintf(stderr, "==> %s.{info,data,rsrc}\n", namebuf);
  307. #else    MPW
  308.     if (verbose)
  309.         fprintf(stderr, "==> \"%s\"\n", mh.m_name);
  310.     BlockMove (mh.m_author, (char *)&f_creator, 4);
  311.     BlockMove (mh.m_type, (char *)&f_type, 4);
  312.     c2pstr(mh.m_name);
  313.     (void)Create (mh.m_name, 0, f_creator, f_type);
  314.     p2cstr(mh.m_name);
  315. #endif    MPW
  316. }
  317.  
  318. /* print out header information in human-readable format */
  319. print_header()
  320. {
  321.     char *ctime();
  322.  
  323.     printf("macname: %s\n", mh.m_name);
  324.     printf("filetype: %.4s, ", mh.m_type);
  325.     printf("author: %.4s, ", mh.m_author);
  326.     printf("flags: 0x%x\n", mh.m_flags);
  327.     if (qformat) {
  328.         printf("data length: %ld, ", mh.m_datalen);
  329.         printf("rsrc length: %ld\n", mh.m_rsrclen);
  330.     }
  331.     if (!pre_beta) {
  332.         printf("create time: %s", ctime(&mh.m_createtime));
  333.     }
  334. }
  335.  
  336. process_forks()
  337. {
  338.     char    buf[128];
  339.     
  340.     if (qformat) {
  341.         /* read data and resource forks of .hqx file */
  342. #ifdef    MPW
  343.         //if (mh.m_datalen > 0)
  344.             do_q_fork(mh.m_name, mh.m_datalen, TRUE);
  345.         //if (mh.m_rsrclen > 0)
  346.             do_q_fork(mh.m_name, mh.m_rsrclen, FALSE);
  347. #else    MPW
  348.         if (mh.m_datalen > 0)
  349.             do_q_fork(files.f_data, mh.m_datalen, TRUE);
  350.         if (mh.m_rsrclen > 0)
  351.             do_q_fork(files.f_rsrc, mh.m_rsrclen, FALSE);
  352. #endif    MPW
  353.     }
  354.     else
  355.         do_o_forks();
  356.     fgets(buf, 128, ifp);
  357. }
  358.  
  359. /* write out .info file from information in the mh structure */
  360. forge_info()
  361. {
  362.     static char buf[DATABYTES];
  363. #ifndef    MPW
  364.     char *np;
  365.     FILE *fp;
  366.     int n;
  367.     long tdiff;
  368.     struct tm *tp;
  369. #ifdef BSD
  370.     struct timeb tbuf;
  371. #else
  372.     long bs;
  373. #endif
  374.     for (np = mh.m_name; *np; np++)
  375.         if (*np == '_') *np = ' ';
  376.  
  377.     buf[H_NLENOFF] = n = np - mh.m_name;
  378.     strncpy(buf + H_NAMEOFF, mh.m_name, n);
  379.     strncpy(buf + H_TYPEOFF, mh.m_type, 4);
  380.     strncpy(buf + H_AUTHOFF, mh.m_author, 4);
  381.     put2(buf + H_FLAGOFF, mh.m_flags & ~F_LOCKED);
  382.     if (pre_beta) {
  383.         put4(buf + H_OLD_DLENOFF, mh.m_datalen);
  384.         put4(buf + H_OLD_RLENOFF, mh.m_rsrclen);
  385.     }
  386.     else {
  387.         put4(buf + H_DLENOFF, mh.m_datalen);
  388.         put4(buf + H_RLENOFF, mh.m_rsrclen);
  389.  
  390.         /* convert unix file time to mac time format */
  391. #ifdef BSD
  392.         ftime(&tbuf);
  393.         tp = localtime(&tbuf.time);
  394.         tdiff = TIMEDIFF - tbuf.timezone * 60;
  395.         if (tp->tm_isdst)
  396.             tdiff += 60 * 60;
  397. #else
  398.         /* I hope this is right! -andy */
  399.         time(&bs);
  400.         tp = localtime(&bs);
  401.         tdiff = TIMEDIFF - timezone;
  402.         if (tp->tm_isdst)
  403.             tdiff += 60 * 60;
  404. #endif
  405.         put4(buf + H_CTIMOFF, mh.m_createtime + tdiff);
  406.         put4(buf + H_MTIMOFF, mh.m_modifytime + tdiff);
  407.     }
  408.     fp = fopen(files.f_info, "w");
  409.     if (fp == NULL) {
  410.         perror("info file");
  411.         exit(-1);
  412.     }
  413.     fwrite(buf, 1, DATABYTES, fp);
  414.     fclose(fp);
  415. #else    MPW
  416.     ParamBlockRec    pb;
  417.  
  418.     strcpy (buf, mh.m_name);
  419.     c2pstr (buf);
  420.     pb.fileParam.ioNamePtr = buf;
  421.     pb.fileParam.ioVRefNum = 0;
  422.     pb.fileParam.ioFVersNum = 0;
  423.     pb.fileParam.ioFDirIndex = 0;
  424.     pb.fileParam.ioResult = 0;
  425.     (void)PBGetFInfo (&pb, FALSE);
  426.     
  427.     pb.fileParam.ioFlFndrInfo.fdFlags = mh.m_flags;
  428. /*
  429.     pb.ioFlCrDat = mh.m_createtime;
  430.     pb.ioFlMdDat = mh.m_modifytime;
  431. */    
  432.     (void)PBSetFInfo (&pb, FALSE);
  433.     
  434. #endif    MPW
  435. }
  436.  
  437. /* eat characters until header detected, return which format */
  438. find_header()
  439. {
  440.     int c, at_bol;
  441.     char ibuf[BUFSIZ];
  442.  
  443.     /* look for "(This file ...)" line */
  444.     while (fgets(ibuf, BUFSIZ, ifp) != NULL) {
  445.         if (strncmp(ibuf, "(This file", 10) == 0)
  446.             break;
  447.         /* echo mail msg to stdout */
  448.         if (verbose) fputs (ibuf, stdout);
  449.     }
  450.     fflush(stdout);
  451.     at_bol = 1;
  452.     while ((c = getc(ifp)) != EOF) {
  453.         switch (c) {
  454.         case '\n':
  455.         case '\r':
  456.             at_bol = 1;
  457.             break;
  458.         case ':':
  459.             if (at_bol)    /* q format */
  460.                 return 1;
  461.             break;
  462.         case '#':
  463.             if (at_bol) {    /* old format */
  464.                 ungetc(c, ifp);
  465.                 return 0;
  466.             }
  467.             break;
  468.         default:
  469.             at_bol = 0;
  470.             break;
  471.         }
  472.     }
  473.  
  474.     if (!header_found)
  475.         fprintf(stderr, "Couldn't find header\n");
  476.     exit(0);
  477.     /* NOTREACHED */
  478. }
  479.  
  480. static unsigned int crc;
  481.  
  482. short get2q();
  483. long get4q();
  484.  
  485. /* read header of .hqx file */
  486. do_q_header(macname)
  487. char *macname;
  488. {
  489.     char namebuf[256];        /* big enough for both att & bsd */
  490.     int n;
  491.     unsigned int calc_crc, file_crc;
  492.  
  493.     crc = 0;            /* compute a crc for the header */
  494.     q_init();            /* reset static variables */
  495.  
  496.     n = getq();            /* namelength */
  497.     n++;                /* must read trailing null also */
  498.     getqbuf(namebuf, n);        /* read name */
  499.     if (macname[0] == '\0')
  500.         macname = namebuf;
  501.  
  502.     n = strlen(macname);
  503.     if (n > NAMEBYTES)
  504.         n = NAMEBYTES;
  505.     strncpy(mh.m_name, macname, n);
  506.     mh.m_name[n] = '\0';
  507.  
  508.     getqbuf(mh.m_type, 4);
  509.     getqbuf(mh.m_author, 4);
  510.     mh.m_flags = get2q();
  511.     mh.m_datalen = get4q();
  512.     mh.m_rsrclen = get4q();
  513.  
  514.     comp_q_crc(0);
  515.     comp_q_crc(0);
  516.     calc_crc = crc;
  517.     file_crc = get2q();
  518.     /* no files no open at this point */
  519.     verify_crc(calc_crc, file_crc);
  520. }
  521.  
  522. do_q_fork(fname, len, dataFork)
  523. char *fname;
  524. register long len;
  525. Boolean dataFork;
  526. {
  527.     register int c, i;
  528.     unsigned int calc_crc, file_crc;
  529.  
  530. #ifdef    MPW
  531. #define    BSIZE 512
  532.     ParamBlockRec    pb;
  533.     register char    *p;
  534.     register int    count;
  535.     char            buf[BSIZE];
  536.     
  537.     c2pstr (fname);
  538.     pb.ioParam.ioCompletion = NULL;
  539.     pb.ioParam.ioNamePtr = fname;
  540.     pb.ioParam.ioVRefNum = 0;
  541.     pb.ioParam.ioVersNum = 0;
  542.     pb.ioParam.ioMisc = NULL;
  543.     pb.ioParam.ioPermssn = fsWrPerm;
  544.     
  545.     if (dataFork) {
  546.         if (PBOpen(&pb, FALSE) != noErr) {
  547.             fprintf(stderr, "trouble opening data fork\n");
  548.             exit (-1);
  549.         }
  550.     }
  551.     else {
  552.         if (PBOpenRF (&pb, FALSE) != noErr) {
  553.             fprintf(stderr, "trouble opening resource fork\n");
  554.             exit (-1);
  555.         }
  556.     }    
  557.     p2cstr (fname);
  558.     pb.ioParam.ioBuffer = &buf;
  559.     pb.ioParam.ioPosMode = fsAtMark;
  560.     pb.ioParam.ioPosOffset = 0L;
  561.     pb.ioParam.ioReqCount = BSIZE;
  562.     p = buf;
  563.     count = 0;
  564. #else    MPW
  565.     FILE *outf;
  566.  
  567.     outf = fopen(fname, "w");
  568.  
  569.     if (outf == NULL) {
  570.         perror(fname);
  571.         exit(-1);
  572.     }
  573. #endif    MPW
  574.  
  575.     crc = 0;    /* compute a crc for a fork */
  576.  
  577.     if (len)
  578.         for (i = 0; i < len; i++) {
  579.             if ((c = getq()) == EOF) {
  580.                 fprintf(stderr, "unexpected EOF\n");
  581.                 #ifdef    MPW
  582.                     PBClose(&pb, FALSE);
  583.                     FlushVol (NULL, 0);
  584.                 #else    MPW
  585.                     fclose(outf);
  586.                 #endif    MPW
  587.                 exit(2);
  588.             }
  589. #ifdef    MPW
  590.             *p++ = c;
  591.             count++;
  592.             if (count & 0x0F) SpinCursor(1);
  593.             if (count == BSIZE) {
  594.                 /* buffer full */
  595.                 (void) PBWrite (&pb, FALSE);
  596.                 count = 0;
  597.                 p = buf;
  598.             }
  599. #else    MPW                
  600.             putc(c, outf);
  601. #endif    MPW
  602.         }
  603.  
  604.     comp_q_crc(0);
  605.     comp_q_crc(0);
  606.     calc_crc = crc;
  607.     file_crc = get2q();
  608. #ifdef    MPW
  609.     if (count != 0) {
  610.         /* write out the last block */
  611.         SpinCursor(1);
  612.         pb.ioParam.ioReqCount = count;
  613.         (void) PBWrite (&pb, FALSE);
  614.     }
  615.     PBClose(&pb, FALSE);
  616.     FlushVol (NULL, 0);
  617. #else    MPW
  618.     fclose(outf);
  619. #endif    MPW
  620.     /* check CRC: we've written out a duff block but it doesn't matter */
  621.     verify_crc(calc_crc, file_crc);
  622. }
  623.  
  624. /* verify_crc(); -- check if crc's check out */
  625. verify_crc(calc_crc, file_crc)
  626. unsigned int calc_crc, file_crc;
  627. {
  628.     calc_crc &= WORDMASK;
  629.     file_crc &= WORDMASK;
  630.  
  631.     if (calc_crc != file_crc) {
  632.         fprintf(stderr, "CRC error\n---------\n");
  633.         fprintf(stderr, "CRC in file:\t0x%x\n", file_crc);
  634.         fprintf(stderr, "calculated CRC:\t0x%x\n", calc_crc);
  635.         exit(3);
  636.     }
  637. }
  638.  
  639. static int eof;
  640. static char obuf[3];
  641. static char *op, *oend;
  642. static int rep;
  643.  
  644. /* initialize static variables for q format input */
  645. q_init()
  646. {
  647.     eof = 0;
  648.     op = obuf;
  649.     oend = obuf + sizeof obuf;
  650.     rep = 0;
  651. }
  652.  
  653. /* get2q(); q format -- read 2 bytes from input, return short */
  654. short
  655. get2q()
  656. {
  657.     register int c;
  658.     short value = 0;
  659.  
  660.     c = getq();
  661.     value = (c & BYTEMASK) << 8;
  662.     c = getq();
  663.     value |= (c & BYTEMASK);
  664.  
  665.     return value;
  666. }
  667.  
  668. /* get4q(); q format -- read 4 bytes from input, return long */
  669. long
  670. get4q()
  671. {
  672.     register int c, i;
  673.     long value = 0L;
  674.  
  675.     for (i = 0; i < 4; i++) {
  676.         c = getq();
  677.         value <<= 8;
  678.         value |= (c & BYTEMASK);
  679.     }
  680.     return value;
  681. }
  682.  
  683. /* getqbuf(); q format -- read n characters from input into buf */
  684. /*        All or nothing -- no partial buffer allowed */
  685. getqbuf(buf, n)
  686. register char *buf;
  687. register int n;
  688. {
  689.     register int c, i;
  690.  
  691.     for (i = 0; i < n; i++) {
  692.         if ((c = getq()) == EOF)
  693.             return EOF;
  694.         *buf++ = c;
  695.     }
  696.     return 0;
  697. }
  698.  
  699. #define RUNCHAR 0x90
  700.  
  701. /* q format -- return one byte per call, keeping track of run codes */
  702. getq()
  703. {
  704.     register int c;
  705.  
  706.     if ((c = getq_nocrc()) == EOF)
  707.         return EOF;
  708.     comp_q_crc((unsigned)c);
  709.     return c;
  710. }
  711.  
  712. getq_nocrc()
  713. {
  714.     static int lastc;
  715.     int c;
  716.  
  717.     if (rep) {
  718.         rep--;
  719.         return lastc;
  720.     }
  721.     if ((c = getq_raw()) == EOF) {
  722.         return EOF;
  723.     }
  724.     if (c == RUNCHAR) {
  725.         if ((rep = getq_raw()) == EOF)
  726.             return EOF;
  727.         if (rep != 0) {
  728.             /* already returned one, about to return another */
  729.             rep -= 2;
  730.             return lastc;
  731.         }
  732.         else {
  733.             lastc = RUNCHAR;
  734.             return RUNCHAR;
  735.         }
  736.     }
  737.     else {
  738.         lastc = c;
  739.         return c;
  740.     }
  741. }
  742.  
  743. /* q format -- return next 8 bits from file without interpreting run codes */
  744. getq_raw()
  745. {
  746.     char ibuf[4];
  747.     register char *ip = ibuf, *iend = ibuf + sizeof ibuf;
  748.     int c;
  749.  
  750.     if (op == obuf) {
  751.         for (ip = ibuf; ip < iend; ip++) {
  752.             if ((c = get6bits()) == EOF)
  753.                 if (ip <= &ibuf[1])
  754.                     return EOF;
  755.                 else if (ip == &ibuf[2])
  756.                     eof = 1;
  757.                 else
  758.                     eof = 2;
  759.             *ip = (char)(c & BYTEMASK);
  760.         }
  761.         obuf[0] = (ibuf[0] << 2 | ibuf[1] >> 4);
  762.         obuf[1] = (ibuf[1] << 4 | ibuf[2] >> 2);
  763.         obuf[2] = (ibuf[2] << 6 | ibuf[3]);
  764.     }
  765.     if ((eof) & (op >= &obuf[eof]))
  766.         return EOF;
  767.     /*
  768.     fprintf (stderr, "c = %c %02x\n",
  769.                      (*op > ' ')? (*op & BYTEMASK) :'.',
  770.                      *op & BYTEMASK);
  771.     */
  772.     c = *op++;
  773.     if (op >= oend)
  774.         op = obuf;
  775.     return (c & BYTEMASK);
  776. }
  777.  
  778. /*
  779. char tr[] = "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
  780.              0 123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
  781.              0                1               2               3 
  782. trlookup is used to translate by direct lookup.  The input character
  783. is an index into trlookup.  If the result is 0xFF, a bad char has been read.
  784. Added by:  Dan LaLiberte, liberte@uiucdcs.Uiuc.ARPA, ihnp4!uiucdcs!liberte
  785. */
  786. char trlookup[83] = {     0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
  787.             0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0xFF, 0xFF,
  788.             0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0xFF,
  789.             0x14, 0x15, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
  790.             0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
  791.             0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0xFF,
  792.             0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0xFF,
  793.             0x2C, 0x2D, 0x2E, 0x2F, 0xFF, 0xFF, 0xFF, 0xFF,
  794.             0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0xFF,
  795.             0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0xFF, 0xFF,
  796.             0x3D, 0x3E, 0x3F };
  797.  
  798. /* q format -- decode one byte into 6 bit binary */
  799. get6bits()
  800. {
  801.     register int c;
  802.     register int tc;
  803.  
  804.     while (1) {
  805.         c = getc(ifp) & BYTEMASK;
  806.         switch ((char)c) {
  807.         case '\n':
  808.         case '\r':
  809.             continue;
  810.         case ':':
  811.         case EOF:
  812.             return EOF;
  813.         default:
  814.             tc = c - (int)' ';
  815.              tc = (tc < 83) ? trlookup[tc] : 0xff;
  816. /*            fprintf(stderr, "c = '%c' %02x tc = %4x\n", c, c, tc);*/
  817.             if (tc != 0xff)
  818.                 return (tc);
  819.             fprintf(stderr, "bad char: '%c'\n", c);
  820.             return EOF;
  821.         }
  822.     }
  823. }
  824.  
  825.  
  826. #define CRCCONSTANT 0x1021
  827.  
  828. comp_q_crc(c)
  829. register unsigned int c;
  830. {
  831.     register int i;
  832.     register unsigned long temp = crc;
  833.  
  834.     for (i=0; i<8; i++) {
  835.         c <<= 1;
  836.         if ((temp <<= 1) & WORDBIT)
  837.             temp = (temp & WORDMASK) ^ CRCCONSTANT;
  838.         temp ^= (c >> 8);
  839.         c &= BYTEMASK;
  840.     }
  841.     crc = temp;
  842. }
  843.  
  844. /* old format -- process .hex and .hcx files */
  845. do_o_header(macname, filename)
  846. char *macname, *filename;
  847. {
  848.     char namebuf[256];        /* big enough for both att & bsd */
  849.     char ibuf[BUFSIZ];
  850.     int n;
  851.  
  852.     /* set up name for output files */
  853.     if (macname[0] == '\0') {
  854.         strcpy(namebuf, filename);
  855.  
  856.         /* strip directories */
  857.         macname = search_last(namebuf, '/');
  858.         if (macname == NULL)
  859.             macname = namebuf;
  860.         else
  861.             macname++;
  862.  
  863.         /* strip extension */
  864.         n = strlen(macname);
  865.         if (n > 4) {
  866.             n -= 4;
  867.             if (macname[n] == '.' && macname[n+1] == 'h'
  868.                         && macname[n+3] == 'x')
  869.                 macname[n] = '\0';
  870.         }
  871.     }
  872.     n = strlen(macname);
  873.     if (n > NAMEBYTES)
  874.         n = NAMEBYTES;
  875.     strncpy(mh.m_name, macname, n);
  876.     mh.m_name[n] = '\0';
  877.  
  878.     /* read "#TYPEAUTH$flag"  line */
  879.     if (fgets(ibuf, BUFSIZ, ifp) == NULL) {
  880.         fprintf(stderr, "unexpected EOF\n");
  881.         exit(2);
  882.     }
  883.     n = strlen(ibuf);
  884.     if (n >= 7 && ibuf[0] == '#' && ibuf[n-6] == '$') {
  885.         if (n >= 11)
  886.             strncpy(mh.m_type, &ibuf[1], 4);
  887.         if (n >= 15)
  888.             strncpy(mh.m_author, &ibuf[5], 4);
  889.         sscanf(&ibuf[n-5], "%4hx", &mh.m_flags);
  890.     }
  891. }
  892.  
  893. do_o_forks()
  894. {
  895.     char ibuf[BUFSIZ];
  896.     int forks = 0, found_crc = 0;
  897.     unsigned int calc_crc, file_crc;
  898.     extern long make_file();
  899. #ifdef    MPW
  900.     OSType    f_creator, f_type;
  901. #endif    MPW
  902.  
  903.  
  904.     crc = 0;    /* calculate a crc for both forks */
  905. #ifndef    MPW
  906.     /* create empty files ahead of time */
  907.     close(creat(files.f_data, 0666));
  908.     close(creat(files.f_rsrc, 0666));
  909. #else    MPW
  910.     BlockMove (mh.m_author, (char *)&f_creator, 4);
  911.     BlockMove (mh.m_type, (char *)&f_type, 4);
  912.     (void)Create (mh.m_name, 0, f_creator, f_type);
  913. #endif    MPW
  914.  
  915.     while (!found_crc && fgets(ibuf, BUFSIZ, ifp) != NULL) {
  916.         if (forks == 0 && strncmp(ibuf, "***COMPRESSED", 13) == 0) {
  917.             compressed++;
  918.             continue;
  919.         }
  920.         if (strncmp(ibuf, "***DATA", 7) == 0) {
  921.             mh.m_datalen = make_file(files.f_data, compressed);
  922.             forks++;
  923.             continue;
  924.         }
  925.         if (strncmp(ibuf, "***RESOURCE", 11) == 0) {
  926.             mh.m_rsrclen = make_file(files.f_rsrc, compressed);
  927.             forks++;
  928.             continue;
  929.         }
  930.         if (compressed && strncmp(ibuf, "***CRC:", 7) == 0) {
  931.             found_crc++;
  932.             calc_crc = crc;
  933.             sscanf(&ibuf[7], "%x", &file_crc);
  934.             break;
  935.         }
  936.         if (!compressed && strncmp(ibuf, "***CHECKSUM:", 12) == 0) {
  937.             found_crc++;
  938.             calc_crc = crc & BYTEMASK;
  939.             sscanf(&ibuf[12], "%x", &file_crc);
  940.             file_crc &= BYTEMASK;
  941.             break;
  942.         }
  943.     }
  944.  
  945.     if (found_crc)
  946.         verify_crc(calc_crc, file_crc);
  947.     else {
  948.         fprintf(stderr, "missing CRC\n");
  949.         exit(3);
  950.     }
  951. }
  952.  
  953. long
  954. make_file(fname, compressed)
  955. char *fname;
  956. int compressed;
  957. {
  958.     char ibuf[BUFSIZ];
  959.     FILE *outf;
  960.     register long nbytes = 0L;
  961.  
  962.     outf = fopen(fname, "w");
  963.     if (outf == NULL) {
  964.         perror(fname);
  965.         exit(-1);
  966.     }
  967.  
  968.     while (fgets(ibuf, BUFSIZ, ifp) != NULL) {
  969.         if (strncmp(ibuf, "***END", 6) == 0)
  970.             break;
  971.         if (compressed)
  972.             nbytes += comp_to_bin(ibuf, outf);
  973.         else
  974.             nbytes += hex_to_bin(ibuf, outf);
  975.     }
  976.  
  977.     fclose(outf);
  978.     return nbytes;
  979. }
  980.  
  981. comp_c_crc(c)
  982. unsigned char c;
  983. {
  984.     crc = (crc + c) & WORDMASK;
  985.     crc = ((crc << 3) & WORDMASK) | (crc >> 13);
  986. }
  987.  
  988. comp_e_crc(c)
  989. unsigned char c;
  990. {
  991.     crc += c;
  992. }
  993.  
  994. #define SIXB(c) (((c)-0x20) & 0x3f)
  995.  
  996. comp_to_bin(ibuf, outf)
  997. char ibuf[];
  998. FILE *outf;
  999. {
  1000.     char obuf[BUFSIZ];
  1001.     register char *ip = ibuf;
  1002.     register char *op = obuf;
  1003.     register int n, outcount;
  1004.     int numread, incount;
  1005.  
  1006.     numread = strlen(ibuf);
  1007.     ip[numread-1] = ' ';        /* zap out the newline */
  1008.     outcount = (SIXB(ip[0]) << 2) | (SIXB(ip[1]) >> 4);
  1009.     incount = ((outcount / 3) + 1) * 4;
  1010.     for (n = numread; n < incount; n++)    /* restore lost spaces */
  1011.         ibuf[n] = ' ';
  1012.  
  1013.     n = 0;
  1014.     while (n <= outcount) {
  1015.         *op++ = SIXB(ip[0]) << 2 | SIXB(ip[1]) >> 4;
  1016.         *op++ = SIXB(ip[1]) << 4 | SIXB(ip[2]) >> 2;
  1017.         *op++ = SIXB(ip[2]) << 6 | SIXB(ip[3]);
  1018.         ip += 4;
  1019.         n += 3;
  1020.     }
  1021.  
  1022.     for (n=1; n <= outcount; n++)
  1023.         comp_c_crc((unsigned)obuf[n]);
  1024.  
  1025.     fwrite(obuf+1, 1, outcount, outf);
  1026.     return outcount;
  1027. }
  1028.  
  1029. hex_to_bin(ibuf, outf)
  1030. char ibuf[];
  1031. FILE *outf;
  1032. {
  1033.     register char *ip = ibuf;
  1034.     register int n, outcount;
  1035.     int c;
  1036.  
  1037.     n = strlen(ibuf) - 1;
  1038.     outcount = n / 2;
  1039.     for (n = 0; n < outcount; n++) {
  1040.         c = hexit(*ip++);
  1041.         comp_e_crc((unsigned)(c = (c << 4) | hexit(*ip++)));
  1042.         fputc(c, outf);
  1043.     }
  1044.     return outcount;
  1045. }
  1046.  
  1047. hexit(c)
  1048. int c;
  1049. {
  1050.     if ('0' <= c && c <= '9')
  1051.         return c - '0';
  1052.     if ('A' <= c && c <= 'F')
  1053.         return c - 'A' + 10;
  1054.  
  1055.     fprintf(stderr, "illegal hex digit: %c", c);
  1056.     exit(4);
  1057.     /* NOTREACHED */
  1058. }
  1059.  
  1060. put2(bp, value)
  1061. char *bp;
  1062. short value;
  1063. {
  1064.     *bp++ = (value >> 8) & BYTEMASK;
  1065.     *bp++ = value & BYTEMASK;
  1066. }
  1067.  
  1068. put4(bp, value)
  1069. char *bp;
  1070. long value;
  1071. {
  1072.     register int i, c;
  1073.  
  1074.     for (i = 0; i < 4; i++) {
  1075.         c = (value >> 24) & BYTEMASK;
  1076.         value <<= 8;
  1077.         *bp++ = c;
  1078.     }
  1079. }
  1080.